import binascii
import os
import threading
import time
from manager import REV_TYPE


class Common(object):
    _instance_lock = threading.Lock()
    _first_init = True

    def __init__(self):
        if self._first_init:
            self.rev_type = None
            self._is_ap_sta_connect = False
            self._is_rev_sensor = False
            self._first_init = False
            self._sensor_io = False
            self._sensor_adc = False
            self._sensor_adc_io = False
        pass

    def __del__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            with cls._instance_lock:
                if not hasattr(cls, '_instance'):
                    Common._instance = super().__new__(cls)
        return Common._instance

    # return bytes to string
    @staticmethod
    def bytes_to_str(bytes_info: bytes):
        return str(binascii.b2a_hex(bytes_info))[2:-1]

    # return bytes to string,except 0x
    @staticmethod
    def bytes_to_adc(byte_l: bytes, byte_h: bytes):
        # print(int(Common.bytes_to_str(byte_l), 16))
        # print(int(Common.bytes_to_str(byte_h), 16))
        return int(Common.bytes_to_str(byte_h), 16) << 8 | int(Common.bytes_to_str(byte_l), 16)

    # return string to binary
    @staticmethod
    def str_to_bin(data: str):
        return bin(int(data, 16))[2:]

    # output index byte of binary
    @staticmethod
    def get_bit_val(binary, index: int):
        if binary & (1 << index):
            return 1
        else:
            return 0

    @staticmethod
    def save_txt(data: str):
        str_name = time.strftime("%Y_%m_%d", time.localtime())
        str_name = os.getcwd() + os.sep + str_name + '_assistant.txt'
        f = open(str_name, 'a+')
        f.write(data)
        f.close()

    def data_invalid(self, index, data: bytes):
        if index != -1:
            print("index:", index)
            head_hex = int(Common.bytes_to_str(data[index:index + 1]), 16)
            if head_hex == 0xA5:
                msg_id_hex = int(Common.bytes_to_str(data[index + 1:index + 2]), 16)
                if msg_id_hex == 0xAB:
                    if self._sensor_adc_io:
                        msg_len_hex = int(Common.bytes_to_str(data[index + 2:index + 3]), 16)
                        if msg_len_hex == 0x20:
                            return True
                        else:
                            return False
                    return False
                else:
                    return False
        else:
            return False

    @staticmethod
    def data_paste_type(data: bytes):
        data1_hex = int(Common.bytes_to_str(data[1:2]), 16)
        if data1_hex == 0xB1:
            return REV_TYPE.IO_DATA
        elif data1_hex == 0xB3:
            return REV_TYPE.ADC_DATA

    @staticmethod
    def data3_paste_io(data3_hex, dict_sensor):
        dict_sensor['change_old_init'] = Common.get_bit_val(data3_hex, 0)
        dict_sensor['change_old_work'] = Common.get_bit_val(data3_hex, 1)
        dict_sensor['change_new_init'] = Common.get_bit_val(data3_hex, 2)
        dict_sensor['change_new_work'] = Common.get_bit_val(data3_hex, 3)
        dict_sensor['change_down'] = Common.get_bit_val(data3_hex, 5)
        dict_sensor['change_up'] = Common.get_bit_val(data3_hex, 4)
        dict_sensor['change_new_paste'] = Common.get_bit_val(data3_hex, 6)
        dict_sensor['dust_bag_on'] = Common.get_bit_val(data3_hex, 7)
        return dict_sensor

    @staticmethod
    def data4_paste_io(data4_hex, dict_sensor):
        dict_sensor['dust_up_open'] = Common.get_bit_val(data4_hex, 0)
        dict_sensor['watering_water_level'] = Common.get_bit_val(data4_hex, 1)
        dict_sensor['dust_drive_error'] = Common.get_bit_val(data4_hex, 2)
        dict_sensor['charge_side_open'] = Common.get_bit_val(data4_hex, 3)
        dict_sensor['charge_old_box_on'] = Common.get_bit_val(data4_hex, 3)
        return dict_sensor

    @staticmethod
    def data5_paste_io(data5_hex, dict_sensor):
        pass

    @staticmethod
    def data6_paste_io(data6_hex, dict_sensor):
        dict_sensor['dust_pressure'] = (int(Common.bytes_to_str(data6_hex), 16) << 10) / 1000
        pass

    @staticmethod
    def data_paste_io(index, data: bytes, dict_sensor):
        data3_hex = int(Common.bytes_to_str(data[index + 31:index + 32]), 16)
        Common.data3_paste_io(data3_hex, dict_sensor)
        # self.data3_paste_io(data3_hex)
        data4_hex = int(Common.bytes_to_str(data[index + 32:index + 33]), 16)
        Common.data4_paste_io(data4_hex, dict_sensor)
        # self.data4_paste_io(data4_hex)
        data5_hex = int(Common.bytes_to_str(data[index + 33:index + 34]), 16)
        Common.data5_paste_io(data5_hex, dict_sensor)
        # self.data5_paste_io(data5_hex)
        data6_hex = int(Common.bytes_to_str(data[index + 34:index + 35]), 16)
        Common.data6_paste_io(data6_hex, dict_sensor)
        # self.data6_paste_io(data6_hex)

    @staticmethod
    def data_paste_adc(index, data: bytes, dict_sensor):
        dict_sensor['charge_v'] = Common.bytes_to_adc(data[index + 4:index + 5], data[index + 3:index + 4])
        Common.save_txt('charge_v:' + str(dict_sensor['charge_v']) + '\n')
        dict_sensor['change_clean_on'] = Common.bytes_to_adc(data[index + 6:index + 7], data[index + 5:index + 6])
        Common.save_txt('change_clean_on:' + str(dict_sensor['change_clean_on']) + '\n')
        dict_sensor['charge_a'] = Common.bytes_to_adc(data[index + 8:index + 9], data[index + 7:index + 8])
        Common.save_txt('charge_a:' + str(dict_sensor['charge_a']) + '\n')
        dict_sensor['change_old_mop_on'] = Common.bytes_to_adc(data[index + 10:index + 11], data[index + 9:index + 10])
        Common.save_txt('change_old_mop_on:' + str(dict_sensor['change_old_mop_on']) + '\n')
        dict_sensor['change_lift_a'] = Common.bytes_to_adc(data[index + 12:index + 13], data[index + 11:index + 12])
        Common.save_txt('change_lift_a:' + str(dict_sensor['change_lift_a']) + '\n')
        dict_sensor['change_new_mop_on'] = Common.bytes_to_adc(data[index + 14:index + 15], data[index + 13:index + 14])
        Common.save_txt('change_new_mop_on:' + str(dict_sensor['change_new_mop_on']) + '\n')
        dict_sensor['change_old_move_a'] = Common.bytes_to_adc(data[index + 16:index + 17], data[index + 15:index + 16])
        Common.save_txt('change_old_move_a:' + str(dict_sensor['change_old_move_a']) + '\n')
        dict_sensor['dust_auto_a'] = Common.bytes_to_adc(data[index + 20:index + 21], data[index + 19:index + 20])
        Common.save_txt('dust_auto_a:' + str(dict_sensor['dust_auto_a']) + '\n')
        dict_sensor['watering_auto_a'] = Common.bytes_to_adc(data[index + 24:index + 25], data[index + 23:index + 24])
        Common.save_txt('watering_auto_a:' + str(dict_sensor['watering_auto_a']) + '\n')
        dict_sensor['watering_leak'] = Common.bytes_to_adc(data[index + 26:index + 27], data[index + 25:index + 26])
        Common.save_txt('watering_leak:' + str(dict_sensor['watering_leak']) + '\n')
        dict_sensor['watering_tank_pos'] = Common.bytes_to_adc(data[index + 28:index + 29], data[index + 27:index + 28])
        Common.save_txt('watering_tank_pos:' + str(dict_sensor['watering_tank_pos']) + '\n')
        dict_sensor['change_new_move_a'] = Common.bytes_to_adc(data[index + 30:index + 31], data[index + 29:index + 30])
        Common.save_txt('change_new_move_a:' + str(dict_sensor['change_new_move_a']) + '\n')
        return dict_sensor

    @staticmethod
    def data_paste(data: bytes, dict_sensor):
        index = data.find(b'\xa5')
        if not Common().data_invalid(index, data):
            return
        Common.data_paste_io(index, data, dict_sensor)
        Common.data_paste_adc(index, data, dict_sensor)
        # if Common.data_paste_type(data) == REV_TYPE.IO_DATA:
        #     Common().set_rev_type(REV_TYPE.IO_DATA)
        #     Common.data_paste_io(data, dict_sensor)
        # elif Common.data_paste_type(data) == REV_TYPE.ADC_DATA:
        #     Common().set_rev_type(REV_TYPE.ADC_DATA)
        #     Common.data_paste_adc(data, dict_sensor)

    def set_rev_type(self, rev_type):
        self.rev_type = rev_type

    def get_rev_type(self):
        return self.rev_type

    def set_ap_sta_connect(self, b: bool):
        self._is_ap_sta_connect = b
        print('set_ap_sta_connect:', self._is_ap_sta_connect)

    def get_ap_sta_connect(self):
        return self._is_ap_sta_connect
    
    def set_rev_sensor(self, b: bool):
        self._is_rev_sensor = b
        print('set_rev_sensor:', self._is_rev_sensor)

    def get_rev_sensor(self):
        return self._is_rev_sensor

    def set_status_io(self, b: bool):
        self._sensor_io = b

    def set_status_adc(self, b: bool):
        self._sensor_adc = b

    def set_status_adc_io(self, b: bool):
        self._sensor_adc_io = b
